package com.intretech.tj.gpp.service

import com.intretech.tj.gpp.entity.DO.Edge
import com.intretech.tj.gpp.entity.DO.RfidNode
import io.agroal.api.AgroalDataSource
import io.quarkus.runtime.StartupEvent
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.event.Observes
import jakarta.inject.Inject

@ApplicationScoped // 声明这是一个应用范围内的 Bean
class MapDatabaseService {

    // 注入 Quarkus 配置好的数据源
    @Inject
    lateinit var dataSource: AgroalDataSource

    /**
     * 监听应用启动事件，用于初始化数据库。
     * @Observes 注解让这个方法在应用启动时自动被调用。
     */
    fun initDatabase(@Observes startupEvent: StartupEvent) {
        val sqlEdge = """
            CREATE TABLE IF NOT EXISTS "edge" (
                id INTEGER PRIMARY KEY,
                rfid_node_start INTEGER NOT NULL,
                rfid_node_end INTEGER NOT NULL,
                weight INTEGER NOT NULL,
                max_speed REAL NOT NULL,
                max_car INTEGER NOT NULL,
                parking_road BOOLEAN NOT NULL,
                edge_long INTEGER NOT NULL DEFAULT 0,
                nav_favors INTEGER
            )
        """.trimIndent()

        val sqlRfidNode = """
            CREATE TABLE IF NOT EXISTS "rfid_node" (
                id INTEGER PRIMARY KEY,
                name TEXT NOT NULL,
                x INTEGER NOT NULL,
                y INTEGER NOT NULL,
                light_id INTEGER,
                capacity INTEGER NOT NULL DEFAULT 1
            )
        """.trimIndent()

        // 使用 use {} 块可以确保数据库连接和声明被自动关闭
        dataSource.connection.use { connection ->
            connection.createStatement().use { statement ->
                statement.executeUpdate(sqlEdge)
                statement.executeUpdate(sqlRfidNode)
            }
        }
        println("✅ 数据库表初始化检查完成。")
    }

    /**
     * 将地图数据写入数据库。
     * 这个方法会先清空旧数据，然后用批量插入的方式写入新数据，效率更高。
     */
    fun writeMapData(edges: List<Edge>, nodes: List<RfidNode>) {
        val insertEdgeSql = "INSERT INTO edge (id, rfid_node_start, rfid_node_end, weight, max_speed, max_car, parking_road, edge_long, nav_favors) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
        val insertNodeSql = "INSERT INTO rfid_node (id, name, x, y, light_id, capacity) VALUES (?, ?, ?, ?, ?, ?)"

        dataSource.connection.use { connection ->
            // 开启事务，确保所有操作要么全部成功，要么全部失败
            connection.autoCommit = false
            try {
                // 1. 清空旧数据
                connection.createStatement().use { statement ->
                    statement.executeUpdate("DELETE FROM edge")
                    statement.executeUpdate("DELETE FROM rfid_node")
                }

                // 2. 批量插入 Edge 数据
                connection.prepareStatement(insertEdgeSql).use { ps ->
                    for (edge in edges) {
                        ps.setInt(1, edge.id)
                        ps.setInt(2, edge.rfidNodeStart)
                        ps.setInt(3, edge.rfidNodeEnd)
                        ps.setInt(4, edge.weight)
                        ps.setDouble(5, edge.maxSpeed)
                        ps.setInt(6, edge.maxCar)
                        ps.setBoolean(7, edge.parkingRoad)
                        ps.setInt(8, edge.edgeLong)
                        // 处理可空字段
                        if (edge.navFavors != null) ps.setInt(9, edge.navFavors) else ps.setNull(9, java.sql.Types.INTEGER)
                        ps.addBatch() // 添加到批处理
                    }
                    ps.executeBatch() // 执行批处理
                }

                // 3. 批量插入 RfidNode 数据
                connection.prepareStatement(insertNodeSql).use { ps ->
                    for (node in nodes) {
                        ps.setInt(1, node.id)
                        ps.setString(2, node.name)
                        ps.setInt(3, node.x)
                        ps.setInt(4, node.y)
                        if (node.lightId != null) ps.setInt(5, node.lightId) else ps.setNull(5, java.sql.Types.INTEGER)
                        ps.setInt(6, node.capacity)
                        ps.addBatch()
                    }
                    ps.executeBatch()
                }

                // 提交事务
                connection.commit()
                println("🗺️ 地图数据写入成功：${edges.size}条边, ${nodes.size}个节点。")
            } catch (e: Exception) {
                // 如果发生错误，回滚事务
                connection.rollback()
                println("❌ 数据写入失败，事务已回滚。错误: ${e.message}")
                throw e // 抛出异常，让调用者知道操作失败
            }
        }
    }
}